class Parent {
  protected x: number

  // 构造方法声明protect, 只能在派生类中被super执行
  protected constructor (x: number) {
    this.x = x
  }

  protected getX () {
    return this.x
  }
}

class Child extends Parent {
  constructor (x: number) {
    super(x) //
  }

  getX (): number {
    // console.log(super.x) //子类内部只能通过super访问父类的protect方法，不能访问protect属性
    return super.getX()
  }
}

// const p = new Parent(123)
const ch = new Child(234)
console.log(ch.getX())

// 只读属性
class ReadOnlyInfo {
  public readonly info: string

  constructor (info: string) {
    this.info = info
  }
}

const rInfo = new ReadOnlyInfo('只能读，不能改')
// rInfo.info = '改一个试试' // Cannot assign to 'info' because it is a read-only property.
console.log(rInfo)

// 参数修饰符(简写)
class A {
  constructor (private name: string) {
    // 使用参数修饰符可以自动帮你把参数绑定到this上
  }
}

const a = new A('Samuel')
console.log(a)

// 静态成员属性
class B {
  public static readonly pi = 3.1415926
  private static num = 2333
}

console.log(B.pi)
// B.pi = 3.14
// console.log(B.num)

// 可选属性/可选参数  set/get
class Human {
  private _name: string
  public age?: number

  constructor (name: string, age?: number, public gender?: string) {
    this._name = name
    this.age = age
  }

  public set name (newVal: string) {
    this._name = newVal
  }

  public get name () {
    return this._name.replace(/./, substring => substring.toUpperCase())
  }
}

const h = new Human('samuel')
h.name = 'zhangboy'
console.log(h.name)

// 抽象类
abstract class MyFile {
  protected constructor (public size: number) {
  }

  public abstract save(): void // 抽象函数,没有函数体
}

class MediaFile extends MyFile {
  constructor (public size: number, public type: string) {
    super(size) // 必须执行父类(抽象类)构造函数
  }

  save (): void {
    console.log('save media file')
  }

  play (): void {
    console.log('play media File')
  }
}

// 类实现接口
interface player {
  supportType: string[],
  play: () => void
}

class MusicPlayer implements player {
  play (): void {
    console.log('play music')
  }

  supportType: string[];

  constructor (...types: string[]) {
    this.supportType = types
  }
}

const player = new MusicPlayer('mp3', 'wav', 'wma', 'acc')
player.play()

// 接口继承类
class Point {
  protected x: number; // 因为是protect，因此只能在内部或者派生类中初始化
  protected y: number;

  protected constructor (x: number, y: number) {
    this.x = x
    this.y = y
  }
}

interface Point3d extends Point {
  z: number;
}

// 因为要初始化protected x,y 所以要继承类
class AcPoint extends Point implements Point3d {
  z: number;

  constructor (x: number, y: number, z: number) {
    super(x, y)
    this.z = 312
  }
}

class TestE {
  public info: string

  constructor () {
    console.log('constructor exec')
    this.info = 'hhh'
  }
}

// c的类型是对象类型且这个对象包含返回类型是T的构造函数。
const testFn1 = <T>(c: new() => T): T => {
  return new c()
}

testFn1(TestE)
